package org.dreamwork.tools.jfx;

import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.stage.Stage;
import org.dreamwork.tools.LocalUtil;
import org.dreamwork.tools.LogFactory;
import org.dreamwork.tools.UpdateManager;
import org.dreamwork.tools.concurrent.IReceiver;
import org.dreamwork.tools.concurrent.Message;
import org.dreamwork.tools.concurrent.SimpleBroadcaster;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Created by seth.yang on 2018/12/6
 */
public class UpdateChecker implements IReceiver {
    @FXML private Label hint, file, speed, indexer;
//    @FXML private CheckBox chk_background;
    @FXML private ProgressBar progress;

//    private String category, version, base, url;

    private Stage stage;

    private SimpleBroadcaster broadcaster = SimpleBroadcaster.getInstance ();

    private final Logger logger = LogFactory.getLogger (UpdateChecker.class);

    public void setStage (Stage stage) {
        this.stage = stage;
        stage.setOnCloseRequest (event -> {
            if (logger.isLoggable (Level.FINE)) {
                logger.fine ("removing listener from broadcaster");
            }
            broadcaster.unregister (UpdateManager.BC_CAT_UPDATE, this);
        });
    }

    @FXML private void cancel () {
        UpdateManager.cancel ();
        if (stage != null) {
            stage.close ();
        }
    }

/*
    @FXML private void runAtBackground () {
        if (stage != null) {
            stage.close ();
        }
    }
*/

    void check () {
        broadcaster.register (UpdateManager.BC_CAT_UPDATE, this);
    }

    @Override
    public void received (Message message) {
        switch (message.what) {
            case UpdateManager.CODE_PROGRESS: {
                Integer count = message.get ("count");
                Integer index = message.get ("index");
                String  name  = message.get ("name");
                setUI (
                        LocalUtil.ui.getString ("label.update.processing"),
                        index + "/" + count,
                        name, null, 0
                );
                break;
            }
            case UpdateManager.CODE_DOWNLOADING: {
                String speed  = message.get ("speed");
                String name   = message.get ("name");
                Integer count = message.get ("count");
                Integer index = message.get ("index");
                Long total    = message.get ("content-length");
                Long size     = message.get ("size");

                if (count == null) count = 0;
                if (index == null) index = 0;
                if (total == null) total = 0L;
                if (size == null) size = 0L;

                setUI (
                        LocalUtil.ui.getString ("label.update.downloading"),
                        index + "/" + count,
                        name, String.valueOf (speed),
                        (double) size / total
                );
                break;
            }
            case UpdateManager.CODE_COMPLETE:
                info ("Update Complete");
                close ();
                break;
            case UpdateManager.CODE_EXCEPTION:
                Exception ex = (Exception) message.arg;
                error (ex.getMessage (), ex);
                break;
        }
    }

    private void setUI (String action, String index, String name, String downloadSpeed, double percent) {
        Platform.runLater (()->{
            hint.setText (LocalUtil.isEmpty (action) ? "" : action);
            indexer.setText (LocalUtil.isEmpty (index) ? "" : index);
            file.setText (LocalUtil.isEmpty (name) ? "" : name);
            speed.setText (LocalUtil.isEmpty (downloadSpeed) ? "" : downloadSpeed);
            progress.setProgress (percent);
        });
    }

    private void close () {
        if (stage != null) {
            if (Platform.isFxApplicationThread ()) {
                stage.close ();
            } else {
                Platform.runLater (()->stage.close ());
            }
        }
    }

    private void info (String message) {
        if (Platform.isFxApplicationThread ()) {
            showInfo (message);
        } else {
            Platform.runLater (()->showInfo (message));
        }
    }

    private static Alert createDialog (Alert.AlertType type, String message) {
        Alert alert = new Alert (type);
        alert.setHeaderText (null);
        alert.setContentText (message);
        alert.getDialogPane ().getStylesheets ().add ("css/buttons.css");

        return alert;
    }

    private static void showInfo (String message) {
        createDialog (Alert.AlertType.INFORMATION, message).showAndWait ();
    }

    private void error (String message, Exception cause) {
        if (Platform.isFxApplicationThread ()) {
            showError (message, cause);
        } else {
            Platform.runLater (()->showError (message, cause));
        }
    }

    private static void showError (String message, Throwable cause) {
        Alert alert = createDialog (Alert.AlertType.ERROR, message);

        StringWriter writer = new StringWriter ();
        PrintWriter pw = new PrintWriter (writer, true);
        cause.printStackTrace (pw);

        TextArea area = new TextArea (writer.getBuffer ().toString ());
        alert.getDialogPane ().setExpandableContent (area);
        alert.showAndWait ();
    }
}